package com.luoyi.util.mpaas.common;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHighlight;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STHighlightColor;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


@Slf4j
public class WordParamTagRed {

    /**
     * 红色
     */
    public static final String FF_0000 = "FF0000";

    /**
     * 正则表达式模式，用于匹配{{}}
     */
    final private static Pattern PATTERN = Pattern.compile("\\{\\{[^}]+\\}\\}");

    /**
     * 匹配 {{&fe:*
     */
    final public static Pattern PATTERN2 = Pattern.compile("^\\{\\{&fe:[a-zA-Z0-9_]+");

    /**
     * 匹配 t.*
     */
    final public static Pattern PATTERN3 = Pattern.compile("^t\\.[a-zA-Z0-9_]+");


    /**
     * 匹配 t.*}}
     */
    final public static Pattern PATTERN4 = Pattern.compile("^t\\.[a-zA-Z0-9_]+\\}\\}");



    /**
     * 执行转换操作
     *
     * @param inFile 输入文件
     * @param outFile 输出文件
     */
    public void execute(File inFile, File outFile) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        XWPFDocument document;
        try {
            // 检查文件是否存在、是否是文件、是否是 .docx 文件
            if (!inFile.exists() || !inFile.isFile() || !inFile.getName().toLowerCase().endsWith(".docx")) {
                log.error("提供的文件不是有效的 .docx 文件: " + inFile.getAbsolutePath());
                return;
            }
            fis = new FileInputStream(inFile);
            document = new XWPFDocument(fis);
            // 段落文本处理
            for (XWPFParagraph paragraph : document.getParagraphs()) {
                paragraphText(paragraph);
            }
            // 表格处理
            for (int i = 0; i < document.getTables().size(); i++) {
                tableText(document.getTables().get(i));
            }
            // 页眉处理
            for (XWPFHeader header : document.getHeaderList()) {
                // 获取页眉中的所有形状
                for (XWPFParagraph paragraph : header.getParagraphs()) {
                    if (paragraph != null) {
                        paragraphText(paragraph);
                    }
                }
            }
            fos = new FileOutputStream(outFile);
            document.write(fos);
            document.close();
        } catch (IOException e) {
            log.error("读取或写入文件时发生错误: " + inFile.getAbsolutePath(), e);
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                log.error("关闭文件流时发生错误", e);
            }
        }
    }

    /**
     * 处理表格文本，将匹配到的文本用红色高亮显示
     *
     * @param xwpfTable 表格
     */
    private void tableText(XWPFTable xwpfTable) {
        for (int i = 0; i < xwpfTable.getRows().size(); i++) {
            int cellSize = xwpfTable.getRow(i).getTableCells().size();
            boolean isTableParam = false;
            for (int j = 0; j < cellSize; j++) {
                StringBuilder cellText = new StringBuilder();
                List<XWPFParagraph> paragraphs = xwpfTable.getRow(i).getCell(j).getParagraphs();
                for (XWPFParagraph paragraph : paragraphs) {
                    cellText.append(paragraph.getText());
                }
                String text = cellText.toString();
                if (j == 0) {
                    // 第一列  匹配 {{&fe:* t.*
                    String[] split = text.split(" ");
                    if (split.length == 2) {
                        Matcher matcher = PATTERN2.matcher(split[0]);
                        boolean matches = matcher.matches();
                        Matcher matcher2 = PATTERN3.matcher(split[1]);
                        boolean matches2 = matcher2.matches();
                        isTableParam = matches && matches2;
                        if (isTableParam) {
                            cellSetRed(xwpfTable, i, j);
                        }
                    }
                } else if (j == cellSize - 1 && isTableParam) {
                    // 最后一列  匹配 t.*}}
                    Matcher matcher = PATTERN4.matcher(text);
                    if (matcher.matches()) {
                        cellSetRed(xwpfTable, i, j);
                    }
                } else {
                    if (isTableParam) {
                        // 中间列 匹配 t.*
                        Matcher matcher = PATTERN3.matcher(text);
                        if (matcher.matches()) {
                            cellSetRed(xwpfTable, i, j);
                        }
                    }
                }
                if (!isTableParam) {
                    // 不是表格参数时，每个cell按段落处理
                    paragraphs.forEach(this::paragraphText);
                }
            }
        }


    }

    private static void cellSetRed(XWPFTable xwpfTable, int i, int j) {
        List<XWPFParagraph> paragraphs = xwpfTable.getRow(i).getCell(j).getParagraphs();
        for (XWPFParagraph paragraph : paragraphs) {
            paragraph.getRuns().forEach(x -> x.setColor(FF_0000));
        }
    }

    private static void copyStyle(XWPFRun sourceRun, XWPFRun targetRun) {
        // 复制字体样式
        targetRun.setBold(sourceRun.isBold());
        targetRun.setItalic(sourceRun.isItalic());
        targetRun.setUnderline(sourceRun.getUnderline());
        targetRun.setFontFamily(sourceRun.getFontFamily());
        if (sourceRun.getFontSizeAsDouble() != null) {
            targetRun.setFontSize(sourceRun.getFontSizeAsDouble());
        }
        targetRun.setColor(sourceRun.getColor());

        // 复制其他样式属性
        targetRun.setCharacterSpacing(sourceRun.getCharacterSpacing());
        targetRun.setTextPosition(sourceRun.getTextPosition());
        targetRun.setStrikeThrough(sourceRun.isStrikeThrough());
        targetRun.setCapitalized(sourceRun.isCapitalized());
        targetRun.setEmbossed(sourceRun.isEmbossed());
        targetRun.setKerning(sourceRun.getKerning());
        targetRun.setSmallCaps(sourceRun.isSmallCaps());
        targetRun.setStrike(sourceRun.isStrike());
        targetRun.setVanish(sourceRun.isVanish());

        // 设置突出显示
        List<CTHighlight> highlightList = sourceRun.getCTR().getRPr().getHighlightList();
        if (CollectionUtil.isNotEmpty(highlightList)) {
            STHighlightColor.Enum val = highlightList.get(0).getVal();
            if (val != null) {
                targetRun.getCTR().getRPr().addNewHighlight().setVal(val);
            }
        }
    }


    /**
     * 处理段落文本，将匹配到的文本用红色高亮显示
     *
     * @param paragraph 段落
     */
    private void paragraphText(XWPFParagraph paragraph) {
        List<XWPFRun> runs = paragraph.getRuns();
        if (runs == null || runs.isEmpty()) {
            return;
        }
        int oldSize = runs.size();

        StringBuilder paragraphText = new StringBuilder();
        for (XWPFRun run : runs) {
            String text = run.getText(0);
            paragraphText.append(text == null ? StrUtil.EMPTY : run.getText(0));
        }

        String text = paragraphText.toString();
        log.info(text);
        Matcher matcher = PATTERN.matcher(text);
        Integer lastEnd = null;
        XWPFRun sourceRun = runs.get(0);
        while (matcher.find()) {
            String match = matcher.group();
            int start = matcher.start();
            int end = matcher.end();

            // 在匹配前添加文本
            lastEnd = lastEnd == null ? 0 : lastEnd;
            if (start > lastEnd) {
                XWPFRun run = paragraph.createRun();
                String substring = paragraphText.substring(lastEnd, start);
                run.setText(substring);
                if (lastEnd == 0) {
                    copyStyle(sourceRun, run);
                } else {
                    XWPFRun runByText = getRunByText(substring, runs, text, lastEnd + 1);
                    copyStyle(runByText, run);
                }
            }

            // 用红色添加匹配的文本
            XWPFRun run = paragraph.createRun();
            run.setText(match);
            CTRPr rPr = run.getCTR().getRPr();
            if (rPr == null) {
                rPr = run.getCTR().addNewRPr();
            }
            // 获取内容所在的run
            XWPFRun textInRun = getRunByText(match, runs, text, start);
            copyStyle(textInRun, run);
            // Red color
            rPr.addNewColor().setVal(FF_0000);
            run.setColor(FF_0000);
            lastEnd = end;
        }

        // 在最后一次匹配后添加剩余的文本
        if (lastEnd  != null && lastEnd < paragraphText.length()) {
            XWPFRun run = paragraph.createRun();
            run.setText(paragraphText.substring(lastEnd));
            copyStyle(sourceRun, run);
        }

        if (lastEnd != null) {
            // 删除原始run
            for (int i = oldSize - 1; i >= 0; i--) {
                paragraph.removeRun(i);
            }
        }
    }

    private XWPFRun getRunByText(String match, List<XWPFRun> runs, String text, int start) {
        if (match.equals(text) || start == 0) {
            return runs.get(0);
        }
        StringBuilder paragraphText = new StringBuilder();
        for (int i = 0; i < runs.size(); i++) {
            XWPFRun run = runs.get(i);
            String textItem = run.getText(0);
            paragraphText.append(textItem == null ? StrUtil.EMPTY : textItem);
            if (paragraphText.toString().length() - 1 >= start) {
                log.info("match={}，找到匹配项，匹配文本：{}", match, run.getText(0));
                log.info("匹配项所在run：{}", i);
                return run;
            }
        }
        return runs.get(0);
    }


    public static void main(String[] args) {
        File inFile = new File("D:\\fileTest\\1t.docx");
        File outFile = new File("D:\\fileTest\\2t.docx");
        WordParamTagRed wordParamTagRed = new WordParamTagRed();
        wordParamTagRed.execute(inFile, outFile);
    }

}
